import copy
import logging
from collections import deque
from threading import Lock

from .messagequeue import Queue
from .templates import (
    ContactList, AbstractUserDict, User,
    MassivePlatform, Chatroom, ChatroomMember)

log = logging.getLogger('storage')


def contact_change(fn):
    def _contact_change(core, *args, **kwargs):
        with core.storageClass.updateLock:
            return fn(core, *args, **kwargs)

    return _contact_change


class Storage(object):
    def __init__(self, core):
        self.userName = None
        self.nickName = None
        self.updateLock = Lock()
        self.memberList = ContactList()
        self.mpList = ContactList()
        self.chatroomList = ContactList()
        self.msgList = Queue(-1)
        self.msg_history = deque(maxlen=300)
        self.lastInputUserName = None
        self.memberList.set_default_value(contactClass=User)
        self.memberList.core = core
        self.mpList.set_default_value(contactClass=MassivePlatform)
        self.mpList.core = core
        self.chatroomList.set_default_value(contactClass=Chatroom)
        self.chatroomList.core = core

    def dumps(self):
        return {
            'userName': self.userName,
            'nickName': self.nickName,
            'memberList': self.memberList,
            'mpList': self.mpList,
            'chatroomList': self.chatroomList,
            'lastInputUserName': self.lastInputUserName,
            'msgHistory': self.msg_history}

    def loads(self, j):
        self.userName = j.get('userName', None)
        self.nickName = j.get('nickName', None)
        self.msg_history.clear()
        for i in j.get('msgHistory', []):
            self.msg_history.append(i)
        del self.memberList[:]
        for i in j.get('memberList', []):
            self.memberList.append(i)
        del self.mpList[:]
        for i in j.get('mpList', []):
            self.mpList.append(i)
        del self.chatroomList[:]
        for i in j.get('chatroomList', []):
            self.chatroomList.append(i)
        # I tried to solve everything in pickle
        # but this way is easier and more storage-saving
        for chatroom in self.chatroomList:
            if 'MemberList' in chatroom:
                for member in chatroom['MemberList']:
                    member.core = chatroom.core
                    member.chatroom = chatroom
            if 'Self' in chatroom:
                chatroom['Self'].core = chatroom.core
                chatroom['Self'].chatroom = chatroom
        self.lastInputUserName = j.get('lastInputUserName', None)

    def search_friends(self, name=None, userName=None, remarkName=None, nickName=None,
                       wechatAccount=None):
        with self.updateLock:
            if (name or userName or remarkName or nickName or wechatAccount) is None:
                return copy.deepcopy(self.memberList[0])  # my own account
            elif userName:  # return the only userName match
                for m in self.memberList:
                    if m['UserName'] == userName:
                        return copy.deepcopy(m)
            else:
                matchDict = {
                    'RemarkName': remarkName,
                    'NickName': nickName,
                    'Alias': wechatAccount, }
                for k in ('RemarkName', 'NickName', 'Alias'):
                    if matchDict[k] is None:
                        del matchDict[k]
                if name:  # select based on name
                    contact = []
                    for m in self.memberList:
                        if any([m.get(k) == name for k in ('RemarkName', 'NickName', 'Alias')]):
                            contact.append(m)
                else:
                    contact = self.memberList[:]
                if matchDict:  # select again based on matchDict
                    friendList = []
                    for m in contact:
                        if all([m.get(k) == v for k, v in matchDict.items()]):
                            friendList.append(m)
                    return copy.deepcopy(friendList)
                else:
                    return copy.deepcopy(contact)

    def search_chatrooms(self, name=None, userName=None):
        with self.updateLock:
            if userName is not None:
                for m in self.chatroomList:
                    if m['UserName'] == userName:
                        return copy.deepcopy(m)
            elif name is not None:
                matchList = []
                for m in self.chatroomList:
                    if name in m['NickName']:
                        matchList.append(copy.deepcopy(m))
                return matchList

    def search_mps(self, name=None, userName=None):
        with self.updateLock:
            if userName is not None:
                for m in self.mpList:
                    if m['UserName'] == userName:
                        return copy.deepcopy(m)
            elif name is not None:
                matchList = []
                for m in self.mpList:
                    if name in m['NickName']:
                        matchList.append(copy.deepcopy(m))
                return matchList

    def append_history(self, message_id):
        self.msg_history.append(message_id)

    def history_check(self, message_id) -> bool:
        if message_id in self.msg_history:
            log.info(message_id)
            return True
        else:
            return False
